package jblip.gui.data.channels;

import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

public class DataChannel<T> extends Observable implements Iterable<T> {

  private static DashboardChannel CHAN_DASHBOARD;
  
  private static BliposphereChannel CHAN_BLIPOSPHERE;
  
  private static final Map<String, TagDataChannel> CHANS_TAG;
  
  private static final Map<String, UserDataChannel> CHANS_USER;

  static {
    CHANS_USER = new HashMap<String, UserDataChannel>();
    CHANS_TAG = new HashMap<String, TagDataChannel>();
  }

  public static UserDataChannel getUserChannel(final String username) {
    UserDataChannel chan = CHANS_USER.get(username);
    if (chan == null) {
      chan = new UserDataChannel(username);
      CHANS_USER.put(username, chan);
      chan.runUpdaterThread();
    }
    return chan;
  }

  public static TagDataChannel getTagChannel(final String tagname) {
    TagDataChannel chan = CHANS_TAG.get(tagname);
    if (chan == null) {
      chan = new TagDataChannel(tagname);
      CHANS_TAG.put(tagname, chan);
      chan.runUpdaterThread();
    }
    return chan;
  }
  
  public static BliposphereChannel getBliposphereChannel() {
    if (CHAN_BLIPOSPHERE == null) {
      CHAN_BLIPOSPHERE = new BliposphereChannel();
      CHAN_BLIPOSPHERE.runUpdaterThread();
    }
    
    return CHAN_BLIPOSPHERE;
  }
  
  public static DashboardChannel getDashboardChannel() {
    if (CHAN_DASHBOARD == null) {
      CHAN_DASHBOARD = new DashboardChannel();
      CHAN_DASHBOARD.runUpdaterThread();
    }
    
    return CHAN_DASHBOARD;
  }

  
  protected ObjectInputStream storage_stream;

  protected final StorageList<T> items;

  protected final String channel_name;

  public DataChannel(final String name) {
    channel_name = name;
    items = new StorageList<T>();
  }

  // Adds an observer and feeds it with up to initial_items latest items.
  public void addObserver(Observer o, final int initial_items) {
    addObserver(o);
    if (initial_items > 0) {
      o.update(this, items.subList(0, initial_items));
    }
  }
  
  public int readBack(int items) {
    return 0;
  }

  public String getName() {
    return channel_name;
  }

  public T getLast() {
    return items.getLast();
  }

  public T getFirst() {
    return items.getFirst();
  }

  public T get(int index) {
    return items.get(index);
  }

  public int size() {
    return items.size();
  }

  @Override
  public Iterator<T> iterator() {
    return items.iterator();
  }
}
